 
-module(pp).
 
-export([read/1,test/0, send/3]).
 
-include("common.hrl").
-include("pp.hrl").
 
-import(pickle, [pickle/2, unpickle/2, byte/0,
                 short/0, sshort/0, int/0, sint/0,
                 long/0, slong/0, list/2, choice/2,
                 optional/1, wrap/2, tuple/1, record/2,
                 binary/1, string/0, wstring/0
                ]).
 
-define(PP_VER, 1).
 
 
host() ->
    string().
 
port() ->
    short().
 
 
nick() ->
    string().
 
pass() ->
    string().

goto() ->
    record(goto, {
             host(),
             port()
            }).

login() ->
    record(login, {
             nick(),
             pass()
            }).

ping() ->
    record(ping, {
             timestamp()
            }).
 
pong() ->
    record(pong, {
             timestamp(),
             timestamp(),
             timestamp()
            }).
 
timestamp() ->
    tuple({int(), int(), int()}).

read(<<?CMD_GOTO, Bin/binary>>) ->
    unpickle(goto(), Bin).

write(R) when is_record(R, goto) ->
    [?CMD_GOTO|pickle(goto(), R)];

write(R) when is_record(R, login) ->
    [?CMD_LOGIN|pickle(login(), R)]; 
 
write(R) when is_record(R, ping) ->
    [?CMD_PING|pickle(ping(), R)];
 
write(R) when is_record(R, pong) ->
    [?CMD_PONG|pickle(pong(), R)].

send(Socket, Data, Ping) ->
    Bin = list_to_binary(write(Data)),
    io:format("SND ~p~n", [Bin]),
    case catch gen_tcp:send(Socket, Bin) of
        ok ->
            ok;
        {error, closed} ->
            ok;
        {error,econnaborted} ->
            ok;
        Any ->
            error_logger:error_report([
                                       {message, "gen_tcp:send error"},
                                       {module, ?MODULE},
                                       {line, ?LINE},
                                       {socket, Socket},
                                       {port_info, erlang:port_info(Socket, connected)},
                                       {data, Data},
                                       {bin, Bin},
                                       {error, Any}
                                      ])
    end,
    ping(Socket, size(Bin), Ping).
 
ping(_, _, false) ->
    ok;
 
ping(Socket, _Size, true) ->
    Bin = list_to_binary(write(#ping{})),
    case catch gen_tcp:send(Socket, Bin) of
        ok ->
            ok;
        {error, closed} ->
            ok;
        {error,econnaborted} ->
            ok;
        Any ->
            error_logger:error_report([
                                       {message, "gen_tcp:ping error"},
                                       {module, ?MODULE},
                                       {line, ?LINE},
                                       {socket, Socket},
                                       {port_info, erlang:port_info(Socket, connected)},
                                       {bin, Bin},
                                       {error, Any}
                                      ])
    end,
    %%stats:sum(packets_out, 2),
    %%stats:sum(bytes_out, Size + size(Bin)),
    ok.
 
test() ->
    ok.